// 检查是否可消除
import {ecs} from "../framework/assets/libs/ecs/ECS";
import {GridModelComponent} from "./gridModelComponent";
import {GridEntity} from "./gridEntity";
import {CellActionTime, CellStatus, CellType, GridSize} from "../cccomponent/enum";
import {CellEntity} from "./cellEntity";
import {CellModelComponent} from "./cellModelComponent";
import {CCComp} from "../common/cccomp";
import {CellView} from "../cccomponent/cellView";
import {
    ExchangeCellComponent,
    GridCheckComponent,
    GridFillSpaceComponent,
    GridInitComponent
} from "./utilsComponent";
import {ViewUtil} from "../framework/assets/core/utils/ViewUtil";
import {EffectEntity} from "./effectEntity";

export class GridCheckSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
    filter(): ecs.IMatcher {
        return ecs.anyOf(GridInitComponent, GridCheckComponent, GridFillSpaceComponent);
    }

    private cycle: number = 0;

    entityEnter(grid: GridEntity): void {
        const gridModel = grid.get(GridModelComponent);
        if (grid.has(GridInitComponent)) {
            grid.remove(GridInitComponent);
            // 初始化 grid
            this.initGrid(gridModel);
        } else if (grid.has(GridCheckComponent)) {
            // 检查是否可消除
            grid.remove(GridCheckComponent);
            console.log('checking grid');
            const needProcess = this.checkGrid(gridModel);
            if (needProcess.length === 0 && gridModel.isCellCanMove()) {
                // 先处理现在的 cell(比如交换)
                gridModel.commitMovement();
                return;
            }
            if (needProcess.length > 0) {
                // 添加消除
                this.processCrush(gridModel, needProcess);
                console.log('process crush');
                gridModel.commitMovement();
                grid.playEliminate(this.cycle);
            } else {
                grid.allowListen();
                this.cycle = 0;
            }
        } else if (grid.has(GridFillSpaceComponent)) {
            grid.remove(GridFillSpaceComponent);
            grid.playContinuousMatch(this.cycle);
            this.fillSpace(gridModel);
            // 处理新的一轮
            this.cycle++;
            gridModel.commitMovement();
        }
    }

    /**
     * 初始化
     * @param gridModel
     */
    initGrid(gridModel: GridModelComponent) {
        // 初始化棋盘, 生成所有的 entity
        // 随机选择 4 种
        gridModel.randomCellTypeList(4);
        for (let i = 1; i <= GridSize.gridRows; i++) {
            gridModel.cells[i] = [];
            for (let j = 1; j <= GridSize.gridColumns; j++) {
                const type = gridModel.getRandomCellType();
                const entity = this.createCell(gridModel, type, i, j);
                gridModel.cells[i][j] = { cellEntity: entity };
                const { result } = this.checkOneCell(gridModel, i, j);
                if (result.length > 2) {
                    // 有3个相同的格子
                    j--;
                    entity.CellModel.cellNode.destroy();
                    entity.destroy();
                    continue;
                }
                // 设置格子的坐标
                const { posX, posY } = entity.CellModel.getPositionByXy();
                entity.CellModel.cellNode.setPosition(posX, posY);
            }
        }
    }

    checkGrid(gridModel: GridModelComponent) {
        // 检查每一个格子
        const checked = [];
        const needProcess: Array<CellEntity> = [];
        for (let i = 1; i <= GridSize.gridRows; i++) {
            for (let j = 1; j <= GridSize.gridColumns; j++) {
                if (checked[i*GridSize.gridRows+j]) {
                    // 已经检查过了
                    continue;
                }
                const { result, newCellStatus, x, y } = this.checkMaxCell(gridModel, i, j);
                let selectedX = x;
                let selectedY = y;
                if (result.length > 2) {
                    for (const r of result) {
                        // 挑选一个格子,生成新格子
                        const entity = gridModel.cells[r.x][r.y].cellEntity;
                        const model = entity.get(CellModelComponent);
                        if (model.isSelect || entity.has(ExchangeCellComponent)) {
                            // 优先选中的 cell, 其次交换中的 cell
                            selectedX = r.x;
                            selectedY = r.y;
                            break;
                        }
                    }
                    // 添加需要处理的 entity
                    for (const r of result) {
                        // 不需要再检查了
                        checked[r.x*GridSize.gridRows+r.y] = true;
                        const entity = gridModel.cells[r.x][r.y].cellEntity;
                        if (newCellStatus !== CellStatus.common && r.x === selectedX && r.y === selectedY) {
                            // 新生成的格子,不消除, 更新当前 cell 的新状态
                            if (newCellStatus === CellStatus.bird) {
                                // 鸟，要生成新的
                                const newEntity = this.createCell(gridModel, CellType.bird, r.x, r.y);
                                const { posX, posY } = newEntity.CellModel.getPositionByXy();
                                newEntity.CellModel.cellNode.setPosition(posX, posY);
                                // 直接处理，不需要动效
                                (entity as CellEntity).toDie(0);
                                gridModel.allowCellMove(entity);
                                gridModel.cells[r.x][r.y] = { cellEntity: newEntity };
                                newEntity.updateStatus(CellStatus.bird);
                                gridModel.allowCellMove(newEntity);
                            } else {
                                if (entity.get(CellModelComponent).status !== CellStatus.common) {
                                    // 需要重新生成一个新cell， 旧的还要处理
                                    this.addUniqueCellEntity(gridModel, entity as CellEntity, needProcess);
                                    // 生成新的 cell
                                    const newEntity = this.createCell(gridModel, entity.get(CellModelComponent).type, r.x, r.y);
                                    const { posX, posY } = newEntity.CellModel.getPositionByXy();
                                    newEntity.CellModel.cellNode.setPosition(posX, posY);
                                    newEntity.updateStatus(newCellStatus);
                                    gridModel.cells[r.x][r.y] = { cellEntity: newEntity };
                                    gridModel.allowCellMove(newEntity);
                                } else {
                                    // 普通状态的 cell，不需要重新生成
                                    (entity as CellEntity).updateStatus(newCellStatus);
                                    gridModel.allowCellMove(entity);
                                }
                            }
                            continue;
                        }
                        let isNew = true;
                        for (const e of needProcess) {
                            if (e.CellModel.x === r.x && e.CellModel.y === r.y) {
                                isNew = false;
                                break;
                            }
                        }
                        if (isNew) {
                            needProcess.push(gridModel.cells[r.x][r.y].cellEntity as CellEntity);
                        }
                    }
                }
            }
        }
        // 获取交换的格子
        const swap = ecs.query(ecs.allOf(ExchangeCellComponent));
        if(this.cycle === 0 && swap.length === 2) {
            const aEntity = swap[0];
            const bEntity = swap[1];
            const aModel = aEntity.get(CellModelComponent);
            const bModel = bEntity.get(CellModelComponent);
            if (aModel.status === CellStatus.bird || bModel.status === CellStatus.bird) {
                const aType = aModel.type;
                const bType = bModel.type;
                if (aModel.status === CellStatus.bird) {
                    aModel.birdType = bType;
                }
                if (bModel.status === CellStatus.bird) {
                    bModel.birdType = aType;
                }
                // 去重
                this.addUniqueCellEntity(gridModel, aEntity as CellEntity, needProcess);
                this.addUniqueCellEntity(gridModel, bEntity as CellEntity, needProcess);
            }
            if (needProcess.length === 0) {
                // 交换回去
                (aEntity as CellEntity).moveBack(CellActionTime.moveTo, 0);
                (bEntity as CellEntity).moveBack(CellActionTime.moveTo, 0);
                // 移除交换状态
                aEntity.remove(ExchangeCellComponent);
                bEntity.remove(ExchangeCellComponent);
                gridModel.allowCellMove(aEntity);
                gridModel.allowCellMove(bEntity);
                gridModel.exchangeCell(aModel.x, aModel.y, bModel.x, bModel.y);
            } else {
                // 删除当前交换状态, 不然下次操作会出错
                aEntity.remove(ExchangeCellComponent);
                bEntity.remove(ExchangeCellComponent);
            }
        }
        return needProcess;
    }

    fillSpace(gridModel: GridModelComponent) {
        // 原来有的格子要向下移动
        for (let j = 1; j <= GridSize.gridColumns; j++) {
            // 查找所有的空格
            let space = 0;
            for (let i = GridSize.gridRows; i > 0; i--) {
                if (!gridModel.cells[i][j]) {
                    space++;
                } else if (space > 0) {
                    // 向下移动
                    const entity = gridModel.cells[i][j].cellEntity;
                    (entity as CellEntity).moveTo(i+space, j, CellActionTime.moveTo * space, 0);
                    gridModel.allowCellMove(entity);
                    gridModel.cells[i+space][j] = gridModel.cells[i][j];
                }
            }
            // 有几个空格，就要生成几个
            if (space === 0) {
                // 一个都不需要生成
                continue;
            }
            for (let i = space; i > 0; i--) {
                const type = gridModel.getRandomCellType();
                // i - space 从 0 行往上排,然后一起下落
                const entity = this.createCell(gridModel, type, i-space, j);
                const { posX, posY } = entity.CellModel.getPositionByXy();
                entity.CellModel.cellNode.setPosition(posX, posY);
                gridModel.cells[i][j] = { cellEntity: entity };
                entity.moveTo(i, j, CellActionTime.moveTo * space, 0);
                gridModel.allowCellMove(entity);
            }
        }
    }

    /**
     * 新建格子
     * @param model grid 节点
     * @param type 格子类型
     * @param x 第几行
     * @param y 第几列
     */
    createCell(model: GridModelComponent, type: string, x: number, y: number): CellEntity {
        const cellEntity = ecs.getEntity<CellEntity>(CellEntity);
        cellEntity.CellModel.cellNode = ViewUtil.createPrefabNode('cells/' + type);
        cellEntity.CellModel.cellNode.parent = model.gridNode;
        cellEntity.CellModel.x = x;
        cellEntity.CellModel.y = y;
        cellEntity.CellModel.type = type;
        // 将 cellView 组件添加进来
        cellEntity.add(cellEntity.CellModel.cellNode.getComponent('CellView') as CCComp);
        // 取消选中的状态
        cellEntity.CellModel.cellNode.getChildByName('select').active = false;
        cellEntity.CellModel.status = CellStatus.common;
        return cellEntity;
    }

    // 处理消除
    processCrush(gridModel: GridModelComponent, needProcess: Array<CellEntity>) {
        // 特殊格子
        let bombs = [];
        for (const entity of needProcess) {
            const cellModel = entity.get(CellModelComponent);
            if (cellModel.status !== CellStatus.common) {
                // 爆炸效果的格子
                bombs.push(entity);
            }
            this.crushCell(gridModel, entity);
        }
        while (bombs.length > 0) {
            const newBombs = [];
            for (const entity of bombs) {
                switch (entity.CellModel.status) {
                    case CellStatus.bird:
                        console.log('is bird');
                        const crushType = entity.CellModel.birdType;
                        if (!crushType) {
                            // 出错了，没有类型
                            debugger;
                        }
                        // 消除所有相同类型的 cell
                        for (let i = 1; i <= GridSize.gridRows; i++) {
                            for (let j = 1; j <= GridSize.gridColumns; j++) {
                                if (gridModel.cells[i][j] && gridModel.cells[i][j].cellEntity.get(CellModelComponent).type === crushType) {
                                    const targetEntity = gridModel.cells[i][j].cellEntity;
                                    const model = targetEntity.get(CellModelComponent);
                                    if (model.status !== CellStatus.common) {
                                        // 鸟消除的是，本格的类型
                                        model.birdType = entity.CellModel.type;
                                        newBombs.push(targetEntity);
                                    }
                                    this.crushCell(gridModel, targetEntity);
                                }
                            }
                        }
                        break;
                    case CellStatus.column:
                        console.log('is column');
                        // 消除一列
                        for (let i = 1; i <= GridSize.gridRows; i++) {
                            if (!gridModel.cells[i][entity.CellModel.y]) {
                                // 没有格子
                                continue;
                            }
                            const targetEntity = gridModel.cells[i][entity.CellModel.y].cellEntity;
                            const model = targetEntity.get(CellModelComponent);
                            if (model.status !== CellStatus.common) {
                                // 又是特殊格子
                                model.birdType = entity.CellModel.type;
                                newBombs.push(targetEntity);
                            }
                            this.crushCell(gridModel, targetEntity);
                        }
                        this.addBombEffect(gridModel, entity, false);
                        break;
                    case CellStatus.line:
                        // 消除一行
                        console.log('is line');
                        for (let j = 1; j <= GridSize.gridColumns; j++) {
                            if (!gridModel.cells[entity.CellModel.x][j]) {
                                // 没有格子
                                continue;
                            }
                            const targetEntity = gridModel.cells[entity.CellModel.x][j].cellEntity;
                            const model = targetEntity.get(CellModelComponent);
                            if (model.status !== CellStatus.common) {
                                // 又是特殊格子
                                model.birdType = entity.CellModel.type;
                                newBombs.push(targetEntity);
                            }
                            this.crushCell(gridModel, targetEntity);
                        }
                        this.addBombEffect(gridModel, entity, true);
                        break;
                    case CellStatus.wrap:
                        // 消掉周围 12 个方块
                        console.log('bomb wrap');
                        for (let i = 1; i <= GridSize.gridRows; i++) {
                            for (let j = 1; j <= GridSize.gridColumns; j++) {
                                const delta = Math.abs(entity.CellModel.x-i) + Math.abs(entity.CellModel.y-j);
                                if (gridModel.cells[i][j] && delta <= 2) {
                                    const targetEntity = gridModel.cells[i][j].cellEntity;
                                    const model = targetEntity.get(CellModelComponent);
                                    if (model.status !== CellStatus.common) {
                                        // 又是特殊格子
                                        model.birdType = entity.CellModel.type;
                                        newBombs.push(targetEntity);
                                    }
                                    this.crushCell(gridModel, targetEntity);
                                }
                            }
                        }
                        break;
                }
            }
            bombs = newBombs;
        }
    }

    // 消除格子动作
    crushCell(gridModel: GridModelComponent, entity: ecs.Entity) {
        const cellModel = entity.get(CellModelComponent);
        if (!gridModel.cells[cellModel.x][cellModel.y]) {
            // 居然没处理就空了
            debugger;
        }
        if (gridModel.cells[cellModel.x][cellModel.y].cellEntity.eid === entity.eid) {
            // 同一个可以置空
            gridModel.cells[cellModel.x][cellModel.y] = null;
        }
        (entity as CellEntity).toDie(0);
        gridModel.allowCellMove(entity);
        // 消除效果
        const effectEntity = ecs.getEntity(EffectEntity);
        const pos = cellModel.getPositionByXy();
        effectEntity.addCrush(pos.posX, pos.posY);
        gridModel.addEffect(effectEntity);
    }

    // 爆炸效果
    addBombEffect(gridModel: GridModelComponent, entity: ecs.Entity, isBombLine?: boolean) {
        const effectEntity = ecs.getEntity(EffectEntity);
        const pos = entity.get(CellModelComponent).getPositionByXy();
        // 爆炸效果
        effectEntity.addBomb(pos.posX, pos.posY, isBombLine);
        gridModel.addEffect(effectEntity);
    }

    // 检查格子是否可消除
    checkOneCell(model: GridModelComponent, x: number, y: number) {
        const checkWithDirection = function (x: number, y: number, direction: Array<{x: number, y: number}>) {
            const queue = [];
            const visited = [];
            visited[x*GridSize.gridRows+y] = true;
            queue.push({ x, y });
            let next = 0;
            while (next < queue.length) {
                const point = queue[next];
                next++;
                const cellModel = model.cells[point.x][point.y];
                if (!cellModel) {
                    // 空格
                    continue;
                }
                // 检查相邻格子的类型(同一行或者同一列)
                for (let i = 0; i < direction.length; i++) {
                    const tmpX = point.x + direction[i].x;
                    const tmpY = point.y + direction[i].y;
                    const row = model.cells[tmpX];
                    if (!row) {
                        // 当前行没有
                        continue;
                    }
                    const targetModel = row[tmpY];
                    if (tmpX < 1 || tmpX > GridSize.gridRows ||
                        tmpY < 1 || tmpY > GridSize.gridColumns ||
                        visited[tmpX*GridSize.gridRows+tmpY] ||
                        !targetModel) {
                        // 没有此格子，此格子已经检查过了
                        continue;
                    }
                    if (cellModel.cellEntity.get(CellModelComponent).type === targetModel.cellEntity.get(CellModelComponent).type) {
                        visited[tmpX*GridSize.gridRows+tmpY] = true;
                        queue.push({ x: tmpX, y: tmpY });
                    }
                }
            }
            return queue;
        }
        // 同一行右边，左边的格子
        const rowResult = checkWithDirection(x, y, [ { x: 0, y: 1 }, { x: 0, y: -1 } ]);
        // 同一列下边，上边的格子
        const colResult = checkWithDirection(x, y, [ { x: 1, y: 0}, { x: -1, y: 0 } ]);
        let result = [];
        let newCellStatus: CellStatus = CellStatus.common;
        if (rowResult.length >= 5 || colResult.length >= 5) {
            // 同一行列消除的格子达到 5 个
            newCellStatus = CellStatus.bird;
        } else if (rowResult.length >= 3 && colResult.length >= 3) {
            newCellStatus = CellStatus.wrap;
        } else if (rowResult.length >= 4) {
            newCellStatus = CellStatus.line;
        } else if (colResult.length >= 4) {
            newCellStatus = CellStatus.column;
        }
        // 合并所有格子
        if (rowResult.length >= 3) {
            result = rowResult;
        }
        if (colResult.length >= 3) {
            this.delDupCell(colResult, result);
        }
        return { result, newCellStatus };
    }

    checkMaxCell(model: GridModelComponent, startX: number, startY: number) {
        const { result, newCellStatus } = this.checkOneCell(model, startX, startY);
        let maxResult = result;
        let maxResultStatus = newCellStatus;
        // 更新 x， y 坐标
        let x = startX;
        let y = startY;
        if (maxResult.length < 3) {
            return { result, newCellStatus, x, y };
        }
        for (const r of result) {
            if (r.x === startX && r.y === startY) {
                continue;
            }
            const tmpResult = this.checkOneCell(model, r.x, r.y);
            if (tmpResult.result.length > maxResult.length) {
                maxResult = tmpResult.result;
                maxResultStatus = tmpResult.newCellStatus;
                x = r.x;
                y = r.y;
            }
        }
        return { result: maxResult, newCellStatus: maxResultStatus, x, y };
    }

    // 去除重复的
    delDupCell(addList: Array<{x: number, y: number}>, result: Array<{x: number, y:number}>) {
        const dup = result.concat();
        addList.forEach(newElem => {
            let isAdd = false;
            dup.forEach(oldElem => {
                if (oldElem.x === newElem.x && oldElem.y === newElem.y) {
                    isAdd = true;
                }
            })
            if (!isAdd) {
                result.push(newElem);
            }
        })
    }

    // 添加唯一entity
    addUniqueCellEntity(gridModel: GridModelComponent, toAdd: CellEntity, needProcess: Array<CellEntity>) {
        let isNew = true;
        for (const e of needProcess) {
            if (e.CellModel.x === toAdd.CellModel.x && e.CellModel.y === toAdd.CellModel.y) {
                isNew = false;
                break;
            }
        }
        if (isNew) {
            needProcess.push(toAdd);
        }
    }
}
